package com.xzkydz.sensor.helper;

import static com.xzkydz.sensor.SensorInit.TAG_SERIAL_PORT;

import android.os.Build;


import com.xzkydz.SerialPort;
import com.xzkydz.sensor.SensorInit;
import com.xzkydz.sensor.utils.CalculationUtils;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.security.InvalidParameterException;
import java.util.Arrays;


/**
 * 串口操作方法
 */
public abstract class SerialHelper{
    private SerialPort mSerialPort;
    private OutputStream mOutputStream;
    private InputStream mInputStream;
    /**
     * 读取线程
     */
    private Thread mReadThread;
    /**
     * 循环发送线程
     */
    private LoopSendThread mSendThread;
    /**
     * Android 设备串口编号
     */
    protected String sPort = "/dev/ttyMT1";
    /**
     * 串口波特率
     */
    private int iBaudRate = 115200;
    /**
     * 线程循环解析数据包的间隔
     */
    private int iDelay = 10;
    /**
     * 是否解析串口数据
     */
    protected boolean parseCom = true;
    /**
     * 串口打开
     */
    protected boolean openCom = false;
    /**
     * 打开串口的情况下，是否读取数据
     */
    protected boolean readCom = true;
    /**
     * 是否开启异或校验
     */
    protected boolean openXor = false;

    /**
     * 循环发送的数据
     */
    private byte[] loopDataBuffer = new byte[]{0x30};

    /**
     * @param parseCom 是否解析数据
     */
    public SerialHelper(boolean parseCom) {
        this.parseCom = parseCom;
        // 串口频率默认为 115200
        this.iBaudRate = 115200;
        // 串口号不同的Android版本发生了改变
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            this.sPort = "/dev/ttyMT2";
        } else {
            this.sPort = "/dev/ttyMT1";
        }
    }

    /**
     * @param sPort     : 串口号
     * @param sBaudRate ： 波特率
     * @param parseCom  ： 是否解析数据包
     */
    public SerialHelper(String sPort, int sBaudRate, boolean parseCom) {
        this.sPort = sPort;
        this.iBaudRate = sBaudRate;
        this.parseCom = parseCom;
    }


    /**
     * 调用JNI，初始化、并打开串口，启动读取线程、发送线程
     *
     * @throws SecurityException
     * @throws IOException
     * @throws InvalidParameterException
     */
    public void open() throws IOException, InvalidParameterException {
        openCom = true;
        readCom = true;
        mSerialPort = new SerialPort(new File(sPort), iBaudRate, 0);
        mOutputStream = mSerialPort.getOutputStream();
        mInputStream = mSerialPort.getInputStream();

        // 根据是否解析数据，开启不同的线程
        mReadThread = new Thread(parseCom ? new ReadCompleteRunnable() : new ReadOriginalRunnable());
        mReadThread.start();

        // 循环发送线程
        mSendThread = new LoopSendThread();
        mSendThread.setSuspendFlag();
        mSendThread.start();

        if (mReadThread.isAlive()) {
            SensorInit.printLog(TAG_SERIAL_PORT, "串口--> 读线程启动");
        }

        if (mSendThread.isAlive()) {
            SensorInit.printLog(TAG_SERIAL_PORT, "串口--> 循环发送线程启动");
        }
    }


    /**
     * 关闭读串口线程，调用JNI关闭串口
     */
    public void close() {
        openCom = false;
        readCom = false;

        if (mReadThread != null) {
            mReadThread.interrupt();
            mReadThread = null;
        }

        if (mSendThread != null) {
            mSendThread.interrupt();
            mSendThread = null;
        }

        if (mSerialPort != null) {
            mSerialPort.close();
            mSerialPort = null;
        }

        if(mOutputStream != null){
            try {
                mOutputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        if(mInputStream != null){
            try {
                mInputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }


    /**
     * 发送字节数组
     *
     * @param bOutArray
     */
    public void send(byte[] bOutArray) {
        try {
            mOutputStream.write(bOutArray);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 发送十六进制字符串
     *
     * @param sHex
     */
    public void sendHex(String sHex) {
        byte[] bOutArray = CalculationUtils.hexToByteArr(sHex);
        send(bOutArray);
    }

    /**
     * 发送文本
     *
     * @param sTxt
     */
    public void sendTxt(String sTxt) {
        byte[] bOutArray = sTxt.getBytes();
        send(bOutArray);
    }

    /**
     * 循环发送数组
     *
     * @param loopDataBuffer
     */
    public void setLoopData(byte[] loopDataBuffer) {
        this.loopDataBuffer = loopDataBuffer;
    }

    /**
     * 循环发送 txt
     *
     * @param sTxt
     */
    public void setTxtLoopData(String sTxt) {
        this.loopDataBuffer = sTxt.getBytes();
    }

    /**
     * 循环发送 十六进制字符串
     *
     * @param sHex
     */
    public void setHexLoopData(String sHex) {
        this.loopDataBuffer = CalculationUtils.hexToByteArr(sHex);
    }


    /**
     * 读取串口中的原始数据，不进行分包和解析操作
     */
    private class ReadOriginalRunnable implements Runnable {
        @Override
        public void run() {
            while (openCom) {
                try {
                    Thread.sleep(iDelay);
                    // 不读取串口
                    if (!readCom) {
                        continue;
                    }

                    if (mInputStream == null) {
                        return;
                    }
                    // 暂存数组的长度
                    byte[] buffer = new byte[500];
                    // 将输入流中的数据放到 buffer中，返回读取的数据长度
                    int size = mInputStream.read(buffer);
                    if (size > 0) {
                        byte[] bufferRes = Arrays.copyOfRange(buffer, 0, size);
                        if (bufferRes != null && bufferRes.length > 0) {
                            onDataReceived(bufferRes);
                        }
                    }

                } catch (InterruptedException e) {
                    e.printStackTrace();
                } catch (Throwable e) {
                    e.printStackTrace();
                    return;
                }
            }
        }
    }

    /**
     * 读取完整数据
     */
    private class ReadCompleteRunnable implements Runnable {
        @Override
        public void run() {
            // 未处理的数据长度
            int currentLength = 0;
            byte[] bufDeal = new byte[512];
            byte[] bufRead = new byte[512];
            while (openCom) {
                if (!readCom) {
                    continue;
                }
                try {
                    // 延时50ms
                    Thread.sleep(iDelay);
                    if (mInputStream == null) {
                        return;
                    }
                    int size = mInputStream.read(bufRead);
                    // arraycopy(源数组, 原数组的起始位置, 目标数组, 目标数组的起始位置, 要复制的元素数目);
                    System.arraycopy(bufRead, 0, bufDeal, currentLength, size);
                    currentLength += size;

                    // 当包的长度大于13时，解析数据包
                    while (currentLength >= 13) {
                        if (bufDeal[0] != 0x4B || bufDeal[1] != 0x59) {
                            System.arraycopy(bufDeal, 1, bufDeal, 0, currentLength - 1);
                            currentLength -= 1;
                            continue;
                        } else {
                            //整个包的长度
                            int factPackLen = (bufDeal[2] & 0xff) + 4;
                            byte[] recData = new byte[factPackLen];
                            if (currentLength < factPackLen) {
                                break;
                            } else {
                                //异或校验
                                if (openXor) {
                                    byte temp = bufDeal[2];
                                    for (int i = 3; i < factPackLen - 1; i++) {
                                        temp ^= bufDeal[i];
                                    }
                                    // 校验通过的逻辑处理
                                    if (temp == bufDeal[factPackLen - 1]) {
                                        System.arraycopy(bufDeal, 0, recData, 0, factPackLen);
                                        onDataReceived(recData);
                                    }
                                } else {
                                    System.arraycopy(bufDeal, 0, recData, 0, factPackLen);
                                    onDataReceived(recData);
                                }
                                //校验通过与否都移除整条数据包
                                System.arraycopy(bufDeal, factPackLen, bufDeal, 0, currentLength - factPackLen);
                                currentLength -= (factPackLen);
                            }
                        }
                    }
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } catch (IOException e) {
                    e.printStackTrace();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    }


    /**
     * 循环发送线程
     */
    private class LoopSendThread extends Thread {
        // 控制线程的执行
        public boolean suspendFlag = true;

        @Override
        public void run() {
            super.run();
            while (openCom) {
                synchronized (this) {
                    while (suspendFlag) {
                        try {
                            wait();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                }
                send(loopDataBuffer);
                try {
                    Thread.sleep(iDelay);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }

        //线程暂停
        public void setSuspendFlag() {
            this.suspendFlag = true;
        }

        //唤醒线程
        public synchronized void setResume() {
            this.suspendFlag = false;
            notify();
        }
    }


    /**
     * 开启循环发送
     */
    public void startSend() {
        if (mSendThread != null) {
            mSendThread.setResume();
        }
    }

    /**
     * 停止循环发送
     */
    public void stopSend() {
        if (mSendThread != null) {
            mSendThread.setSuspendFlag();
        }
    }


    /**
     * 串口发送
     *
     * @param ComPort
     * @param sOut
     */
    public void sendPortData(SerialHelper ComPort, String sOut) {
        if (ComPort != null && openCom) {
            sendHex(sOut);
        }
    }

    /**
     * 关闭串口
     *
     * @param ComPort
     */
    public void CloseComPort(SerialHelper ComPort) {
        if (ComPort != null) {
            stopSend();
            close();
        }
    }


    /**
     * 回调方法
     *
     * @param buffer
     */
    protected abstract void onDataReceived(byte[] buffer);

    public void postException(Exception e) {

    }

    /**
     * 线程循环解析数据包的间隔
     *
     * @param iDelay
     */
    public void setiDelay(int iDelay) {
        this.iDelay = iDelay;
    }

    /**
     * 是否开启异或校验
     *
     * @param openXor
     */
    public void setOpenXor(boolean openXor) {
        this.openXor = openXor;
    }
}